﻿using System.Linq.Expressions;
using Basic.FormCollect.Model;
using Basic.FormDAL;
using Basic.FormModel.DB;
using Basic.FormModel.Model;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.Form.Model;
using Basic.FormRemoteModel.QueryColumn.Model;
using LinqKit;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;

namespace Basic.FormCollect.lmpl
{
    internal class QueryColumnCollect : IQueryColumnCollect
    {
        private readonly IPhysicalQueryColumnDAL _BasicDAL;

        public QueryColumnCollect ( IPhysicalQueryColumnDAL basicDAL )
        {
            this._BasicDAL = basicDAL;
        }

        public Dictionary<long, string> GetLabels ( long[] ids )
        {
            if ( ids.IsNull() )
            {
                return null;
            }
            return this._BasicDAL.Gets(ids, a => new
            {
                a.Id,
                a.ColLabel
            }).ToDictionary(a => a.Id, a => a.ColLabel);
        }
        public Dictionary<long, string> GetColName ( long[] ids )
        {
            return this._BasicDAL.Gets(a => ids.Contains(a.Id), a => new
            {
                a.Id,
                a.ColName
            }).ToDictionary(a => a.Id, a => a.ColName);
        }
        public Dictionary<long, PhyTableCol> GetCols ( long[] tableId )
        {
            return this._BasicDAL.Gets(a => tableId.Contains(a.TableId) && a.ShowMode == PhyColShowMode.Column, a => new
            {
                a.Id,
                a.TableId,
                a.ColName,
                a.ColLabel,
                a.DataType
            }).ToDictionary(a => a.Id, a => new PhyTableCol
            {
                TableId = a.TableId,
                Name = a.ColName,
                Label = a.ColLabel,
                DataType = a.DataType
            });
        }
        public Dictionary<long, PhyTableCol> GetColumns ( long[] ids )
        {
            return this._BasicDAL.Gets(ids, a => new
            {
                a.Id,
                a.TableId,
                a.ColName,
                a.ColLabel,
                a.DataType
            }).ToDictionary(a => a.Id, a => new PhyTableCol
            {
                TableId = a.TableId,
                Name = a.ColName,
                Label = a.ColLabel,
                DataType = a.DataType
            });
        }
        public ColumnSort[] GetSorts ( long tableId, long groupId )
        {
            return this._BasicDAL.GetSorts(tableId, groupId);
        }
        public void SetSort ( ColumnSort sour, ColumnSort to )
        {
            this._BasicDAL.SetSort(sour, to);
        }

        public void SetSort ( KeyValuePair<long, int>[] sort )
        {
            this._BasicDAL.SetSort(sort);
        }
        public long Add ( QueryColumnAdd add )
        {
            if ( this._BasicDAL.IsExists(c => c.TableId == add.TableId && c.ColName == add.ColName) )
            {
                throw new ErrorException("form.query.column.name.repeat");
            }
            DBPhysicalQueryColumn data = add.ConvertMap<QueryColumnAdd, DBPhysicalQueryColumn>();
            data.Sort = this._BasicDAL.GetMaxSort(add.TableId, add.GroupId) + 1;
            return this._BasicDAL.Add(data);
        }
        public DBPhysicalQueryColumn Get ( long id )
        {
            return this._BasicDAL.Get(id);
        }
        public void Delete ( DBPhysicalQueryColumn sour )
        {
            if ( sour.IsSystem )
            {
                throw new ErrorException("form.query.column.not.allow.delete");
            }
            this._BasicDAL.Delete(sour.Id);
        }
        public bool Set ( DBPhysicalQueryColumn sour, QueryColumnSet set )
        {
            if ( sour.IsSystem )
            {
                throw new ErrorException("form.query.column.not.allow.update");
            }
            else if ( sour.ColName != set.ColName && this._BasicDAL.IsExists(c => c.TableId == sour.TableId && c.ColName == set.ColName) )
            {
                throw new ErrorException("form.query.column.name.repeat");
            }
            return this._BasicDAL.Update(sour, set);
        }
        public void Clear ( long id )
        {
            long[] ids = this._BasicDAL.Gets(a => a.FormId == id, a => a.Id);
            if ( ids.IsNull() )
            {
                return;
            }
            this._BasicDAL.Delete(ids);
        }
        public Result Get<Result> ( long columnId ) where Result : class, new()
        {
            return this._BasicDAL.Get<Result>(columnId);
        }
        public Result[] Gets<Result> ( long[] ids ) where Result : class, new()
        {
            return this._BasicDAL.Gets<Result>(ids);
        }
        public Result[] GetsByTableId<Result> ( long tableId, FormGetParam param, Expression<Func<DBPhysicalQueryColumn, Result>> selector ) where Result : class, new()
        {
            ExpressionStarter<DBPhysicalQueryColumn> where = PredicateBuilder.New<DBPhysicalQueryColumn>(a => a.TableId == tableId);
            if ( !param.FuncType.IsNull() )
            {
                where = where.And(a => param.FuncType.Contains(a.FuncType));
            }
            if ( !param.DataType.IsNull() )
            {
                where = where.And(a => param.DataType.Contains(a.DataType));
            }
            if ( !param.ShowMode.IsNull() )
            {
                where = where.And(a => param.ShowMode.Contains(a.ShowMode));
            }
            return this._BasicDAL.Gets<Result>(where, selector);
        }
        public Result[] GetsByFormId<Result> ( long formId, FormGetParam param ) where Result : class, new()
        {
            ExpressionStarter<DBPhysicalQueryColumn> where = PredicateBuilder.New<DBPhysicalQueryColumn>(a => a.FormId == formId);
            if ( !param.FuncType.IsNull() )
            {
                where = where.And(a => param.FuncType.Contains(a.FuncType));
            }
            if ( !param.DataType.IsNull() )
            {
                where = where.And(a => param.DataType.Contains(a.DataType));
            }
            if ( !param.ShowMode.IsNull() )
            {
                where = where.And(a => param.ShowMode.Contains(a.ShowMode));
            }
            if ( param.IsSystem.HasValue && param.IsSystem.Value == false )
            {
                where = where.And(a => a.IsSystem == false);
            }
            return this._BasicDAL.Gets<Result>(where, "Sort");
        }
        public Result[] GetsByFormId<Result> ( long formId, bool isSystem = false ) where Result : class, new()
        {
            if ( isSystem == false )
            {
                return this._BasicDAL.Gets<Result>(a => a.FormId == formId && a.IsSystem == false, "Sort");
            }
            return this._BasicDAL.Gets<Result>(a => a.FormId == formId, "Sort");
        }

        public Result[] GetsByTableId<Result> ( long tableId, bool? isHidden ) where Result : class, new()
        {
            if ( isHidden.HasValue )
            {
                return this._BasicDAL.Gets<Result>(a => a.TableId == tableId && a.IsQueryHide == isHidden.Value, "Sort");
            }
            return this._BasicDAL.Gets<Result>(a => a.TableId == tableId, "Sort");
        }

        public void ClearByTableId ( long tableId )
        {
            long[] ids = this._BasicDAL.Gets(a => a.TableId == tableId, a => a.Id);
            if ( ids.IsNull() )
            {
                return;
            }
            this._BasicDAL.Delete(ids);
        }
        public void ClearByGroupId ( long groupId )
        {
            long[] ids = this._BasicDAL.Gets(a => a.GroupId == groupId, a => a.Id);
            if ( ids.IsNull() )
            {
                return;
            }
            this._BasicDAL.Delete(ids);
        }
        public Result[] Filter<Result> ( long[] ids, FormGetParam param ) where Result : class, new()
        {
            ExpressionStarter<DBPhysicalQueryColumn> where = PredicateBuilder.New<DBPhysicalQueryColumn>(a => ids.Contains(a.Id));
            if ( !param.FuncType.IsNull() )
            {
                where = where.And(a => param.FuncType.Contains(a.FuncType));
            }
            if ( !param.DataType.IsNull() )
            {
                where = where.And(a => param.DataType.Contains(a.DataType));
            }
            if ( !param.ShowMode.IsNull() )
            {
                where = where.And(a => param.ShowMode.Contains(a.ShowMode));
            }
            if ( param.IsSystem.HasValue && param.IsSystem.Value == false )
            {
                where = where.And(a => a.IsSystem == false);
            }
            return this._BasicDAL.Gets<Result>(where, "Sort");
        }
        public long[] Filter ( long[] ids, FormGetParam param )
        {
            ExpressionStarter<DBPhysicalQueryColumn> where = PredicateBuilder.New<DBPhysicalQueryColumn>(a => ids.Contains(a.Id));
            if ( !param.FuncType.IsNull() )
            {
                where = where.And(a => param.FuncType.Contains(a.FuncType));
            }
            if ( !param.DataType.IsNull() )
            {
                where = where.And(a => param.DataType.Contains(a.DataType));
            }
            if ( !param.ShowMode.IsNull() )
            {
                where = where.And(a => param.ShowMode.Contains(a.ShowMode));
            }
            if ( param.IsSystem.HasValue )
            {
                where = where.And(a => a.IsSystem == param.IsSystem.Value);
            }
            return this._BasicDAL.Gets(where, a => a.Id);
        }
    }
}
